'use strict'

const EventEmitter3 = require('eventemitter3');

const logger = require('./logger')('Tracker');
const util = require('./util');
const websocket = require('./websocket');


const ANNOUNCE_INTERVAL = 55000;          // announce 时间间隔


/**
 * Tracker
 *    事件:
 *        'ready': infoHash频道都订阅成功后触发
 *        'join': 有新节点加入时触发, 附加参数 'peerId'
 *        'leave': 有节点离开时触发, 附加参数 'peerId'
 *        'warn': 出现警告时触发, 附加参数 'error'
 *        'error': 出现错误时触发,附加参数 'error'
 *        'stop': infoHash频道取消订阅后(停止)后触发
 */
class Tracker extends EventEmitter3 {
  constructor(ws, infoHash, getAonnounceOptions) {
    if (!(ws instanceof websocket.Ws)) {
      ws = websocket(ws);
    }
    super();
    this.peerId = ws.peerId;
    this._ws = ws;
    this.infoHash = infoHash;
    this.getAonnounceOptions = getAonnounceOptions;

    this._channelName = this._ws.channelPrefix + ':infoHash-' + this.infoHash;
    this._channel = null;
    this.isReady = false;
    this._announceInterval = null;

    this._peerStats = {};
  }

  _getOnlinePeers() {
    if (!this.isReady) return;

    try {
      this._channel.presence().then(context => {
        this._peerStats = {};
        for (let client in context.data) {
          const peerId = context.data[client].user,
            defaultInfo = context.data[client].default_info;

          if (peerId === this.peerId) {
            continue;
          }
          this._peerStats[peerId] = {
            uploaded: 0,
            downloaded: 0,
            left: -1,
          };
          this.emit('join', peerId);
        }
      }).catch(err => {
        logger.warn(err.toSting());
      });
    } catch (err) {
      logger.error(err.toString());
    }
  }

  _announce() {
    const stats = this.getAonnounceOptions();
    this._channel.publish({
      peerId: this.peerId,
      type: 'ANNOUNCE',
      payload: stats,
    });
  }

  start() {
    const handels = {
      'message': message => {
        ` 格式:
          message = {
            channel: 'download_media:infoHash-d5b149248ed22e74a935af9c78984be6cf976275',
            uid: 7,       // 序列号
            data: {
              peerId: 'browser-1cc61d59e24242f3858e684a1a3fb063',   // 发送端peerId
              type: 'ANNOUNCE',                                     // 消息类型
              payload: {                                            // 负载
                uploaded: xxxx,
                downloaded: xxxx,
                left: xxxx,
              }
            }
          }
        `
        const channel = message.channel,
          uid = message.uid,
          data = message.data ? message.data : {},
          peerId = data.peerId,
          type = data.type,
          payload = data.payload ? data.payload : {};

        if (peerId === this.peerId) {
          return;
        }

        switch (type) {
          case 'ANNOUNCE':
            if (peerId in this._peerStats) {
              this._peerStats[peerId] = payload;
            } else {
              this._peerStats[peerId] = payload;
              this.emit('join', peerId);
            }
            break;

          default:
            logger.debug(`recive a message with unkown type "${type}", ignore.`);
            break;
        }
      },
      'join': context => {
        // const channel = context.channel,
        //   peerId = context.data.user,
        //   client = context.data.client,
        //   defaultInfo = context.data.default_info;

        // if (peerId === this._peerId) {
        //   return;
        // }
      },
      'leave': context => {
        const channel = context.channel,
          peerId = context.data.user,
          client = context.data.client,
          defaultInfo = context.data.default_info;

        if (peerId === this._peerId) {
          return;
        }
        // logger.debug(`${peerId} leave ${channel}.`);
        delete this._peerStats[peerId];
        this.emit('leave', peerId);
      },
      'subscribe': context => {
        const channel = context.channel,
          isResubscribe = context.isResubscribe,
          recovered = context.recovered;

        logger.debug(`${isResubscribe ? 'resubscribe' : 'subscribe'} ${channel} success.`);
        this.isReady = true;
        this.emit('ready');

        this._getOnlinePeers();
      },
      'unsubscribe': context => {
        const channel = context.channel;
        if (this.isReady) {
          const warnStr = `lost subscribe ${channel}, auto try subscribe later.`;
          logger.warn(warnStr);
          // 不需要从新订阅处理. 会自动重新订阅
          this.emit('warn', new Error(warnStr));
        } else {
          logger.debug(`unsubscribe ${channel}`);
        }
      },
      'error': error => {
        logger.error(`error: `, error);
        this.emit('error', error);
      }
    }
    this._channel = this._ws.subscribe(this._channelName, handels);
    this._announceInterval = setInterval(() => {
      this._announce();
      setTimeout(() => {
        this._getOnlinePeers();
      }, 5000);
    }, ANNOUNCE_INTERVAL);

  }

  stop() {
    if (!this.isReady) {
      return;
    }
    logger.debug(`stop announce infoHash: ${this.infoHash}.`);
    this.isReady = false;

    if (this._announceInterval) {
      clearInterval(this._announceInterval);
      this._announceInterval = null;
    }
    this._peerStats = {};
    this._channel.removeAllListeners();
    this._channel.unsubscribe();
    this._channel = null;
    this.emit('stop');
  }
}

module.exports.Tracker = Tracker;
